React์ experimental_useFormState ํ ์ ํ์ํ์ฌ React ์ ํ๋ฆฌ์ผ์ด์ ์ ํผ ๊ด๋ฆฌ, ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ํํ์ธ์. ์ค์ฉ์ ์ธ ์์ ๊ฐ ํฌํจ๋ ์ข ํฉ ๊ฐ์ด๋์ ๋๋ค.
React experimental_useFormState: ์ต์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํฅ์๋ ํผ ๊ด๋ฆฌ
ํผ ๊ด๋ฆฌ๋ ์ํธ์์ฉ์ ์ด๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ฐ ์ค์ํ ์ธก๋ฉด์
๋๋ค. ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ
์ฒ๋ฅผ ๊ฐ์ถ React๋ ํผ์ ์ฒ๋ฆฌํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์๋ฒ ์ก์
(Server Actions)์ ๋์
๊ณผ ๊ทธ์ ๋ฐ๋ฅธ experimental_useFormState์ ๊ฐ์ ๊ธฐ๋ฅ ํฅ์์ ๊ฐ๋ฐ์๊ฐ ํนํ ์๋ฒ ์ธก ๋ก์ง๊ณผ ์ํธ์์ฉํ ๋ ํผ ์ฒ๋ฆฌ์ ์ ๊ทผํ๋ ๋ฐฉ์์ ํ์ ํ๊ณ ์์ต๋๋ค. React์ ์๋ฒ ์ปดํฌ๋ํธ ๋ฐ ์ก์
์ ๋ํ ์ง์์ ์ธ ํ๊ตฌ์ ์ผํ์ธ ์ด ์คํ์ ์ธ ํ
์ ํผ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฐ์ํ๋๊ณ ๋ ํจ์จ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
experimental_useFormState๋ ๋ฌด์์ธ๊ฐ?
experimental_useFormState๋ ํนํ ์๋ฒ ์ก์
๊ณผ ์ํธ์์ฉํ๋ ์๋๋ฆฌ์ค์์ ํผ ๊ด๋ฆฌ๋ฅผ ๋จ์ํํ๊ธฐ ์ํด ์ค๊ณ๋ React ํ
์
๋๋ค. ์ด๋ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ํผ ์ํ๋ฅผ ์ ๋ฌํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ฌ ๋ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ๊ณผ ํฅ์๋ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. React ์๋ฒ ์ปดํฌ๋ํธ ๋ฐ ์๋ฒ ์ก์
๊ณผ ์ง์ ํตํฉ๋์ด ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ๋ณ๊ฒฝ์ ํ์ฉํฉ๋๋ค.
์์ธํ ๋ด์ฉ์ ์ดํด๋ณด๊ธฐ ์ ์, ์ด ํ ์ ํ์ฌ ์คํ์ ์ธ ๊ธฐ๋ฅ์ด๋ผ๋ ์ ์ ์ ์ํด์ผ ํฉ๋๋ค. ์ด๋ ํฅํ ๋ฆด๋ฆฌ์ค์์ API๊ฐ ๋ณ๊ฒฝ๋ ์ ์์์ ์๋ฏธํฉ๋๋ค. ๋ฐ๋ผ์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ์ ์คํ๊ฒ ์ฌ์ฉํ๊ณ ์ต์ React ๋ฌธ์๋ฅผ ๊ณ์ ํ์ธํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ experimental_useFormState๋ฅผ ์ฌ์ฉํด์ผ ํ๋๊ฐ?
React์์์ ์ ํต์ ์ธ ํผ ๊ด๋ฆฌ๋ ์ข
์ข
useState ๊ฐ์ ํ
์ด๋ Formik, React Hook Form๊ณผ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ก์ปฌ์์ ํผ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ ํด๋ผ์ด์ธํธ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ๊ฐ๋จํ ํผ ์ํธ์์ฉ์๋ ํจ๊ณผ์ ์ด์ง๋ง, ๋ฐ์ดํฐ ์ ์ถ ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ์ ๊ฐ์ ์๋ฒ ์ธก ์์
์ ์ฒ๋ฆฌํ ๋๋ ๋ฒ๊ฑฐ๋ก์์ง ์ ์์ต๋๋ค. ๋ค์์ experimental_useFormState๊ฐ ์ ๊ณตํ๋ ๋ช ๊ฐ์ง ์ฅ์ ์
๋๋ค:
- ๋จ์ํ๋ ์๋ฒ ์ก์ ํตํฉ: ์ด ํ ์ ํผ์ ์๋ฒ ์ก์ ์ ์ฐ๊ฒฐํ๋ ๊ฒ์ ํจ์ฌ ์ฝ๊ฒ ๋ง๋ญ๋๋ค. ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ณ , ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ์๋ฒ ์ธก ์ค๋ฅ๋ฅผ ํ์ํ๋ ๋ณต์ก์ฑ์ ์ฒ๋ฆฌํฉ๋๋ค.
- ํฅ์๋ ์ฌ์ฉ์ ๊ฒฝํ: ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ํผ ์ํ๋ฅผ ์ ๋ฌํจ์ผ๋ก์จ
experimental_useFormState๋ ๋ ๋ฐ์์ ์ด๊ณ ์ํธ์์ฉ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ํผ์ด ์๋ฒ์์ ์ฒ๋ฆฌ๋๋ ๋์ ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ์ ๊ณตํ ์ ์์ต๋๋ค. - ์ค์ ์ง์ค์ ์ค๋ฅ ์ฒ๋ฆฌ: ์ด ํ ์ ํด๋ผ์ด์ธํธ์ ์๋ฒ ์์ชฝ์์ ํผ ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ์ค์ ์ง์ค์ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ์ค๋ฅ ํ์๋ฅผ ๋จ์ํํ๊ณ ์ผ๊ด๋ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํฉ๋๋ค.
- ์ ์ง์ ํฅ์: ์๋ฒ ์ก์
์
experimental_useFormState์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์ ์ง์ ํฅ์์ ์ง์ํฉ๋๋ค. JavaScript๊ฐ ๋นํ์ฑํ๋ ๊ฒฝ์ฐ์๋ ํผ์ด ์๋ํ์ฌ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ๊ธฐ๋ณธ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค. - ๋ณด์ผ๋ฌํ๋ ์ดํธ ๊ฐ์: ์ ํต์ ์ธ ํผ ๊ด๋ฆฌ ๊ธฐ์ ์ ๋นํด
experimental_useFormState๋ ํ์ํ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋์ ์์ ์ค์ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ ๊น๋ํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
experimental_useFormState ์ฌ์ฉ ๋ฐฉ๋ฒ
experimental_useFormState๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, ๋จผ์ ์๋ฒ ์ก์
์ ์ง์ํ๋ React ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํด์ผ ํฉ๋๋ค (React 18 ์ด์). ๋ํ React ๊ตฌ์ฑ์์ ์คํ์ ์ธ ๊ธฐ๋ฅ์ ํ์ฑํํด์ผ ํฉ๋๋ค. ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฒ๋ค๋ฌ(์: Webpack, Parcel)๋ฅผ ๊ตฌ์ฑํ์ฌ ์คํ์ ์ธ ๊ธฐ๋ฅ์ ํ์ฑํํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค.
๋ค์์ experimental_useFormState๋ฅผ ์ฌ์ฉํ๋ ๊ธฐ๋ณธ์ ์ธ ์์ ์
๋๋ค:
์์ : ๊ฐ๋จํ ๋ฌธ์ ์์
์ด๋ฆ, ์ด๋ฉ์ผ, ๋ฉ์์ง ํ๋๊ฐ ์๋ ๊ฐ๋จํ ๋ฌธ์ ์์์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. experimental_useFormState๋ฅผ ์ฌ์ฉํ์ฌ ํผ ์ ์ถ์ ์ฒ๋ฆฌํ๊ณ ๋ฐ์ํ๋ ๋ชจ๋ ์ค๋ฅ๋ฅผ ํ์ํ ๊ฒ์
๋๋ค.
1. ์๋ฒ ์ก์ ์ ์ํ๊ธฐ:
๋จผ์ , ํผ ์ ์ถ์ ์ฒ๋ฆฌํ ์๋ฒ ์ก์ ์ ์ ์ํด์ผ ํฉ๋๋ค. ์ด ์ก์ ์ ํผ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ํ์ํ ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ฒ๋ฆฌ(์: ์ด๋ฉ์ผ ์ ์ก)๋ฅผ ์ํํฉ๋๋ค.
// server-actions.js
'use server';
import { experimental_useFormState as useFormState } from 'react';
async function submitForm(prevState, formData) {
// ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ ์๋ฎฌ๋ ์ด์
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
if (!name) {
return { error: '์ด๋ฆ์ ํ์ ํญ๋ชฉ์
๋๋ค' };
}
if (!email) {
return { error: '์ด๋ฉ์ผ์ ํ์ ํญ๋ชฉ์
๋๋ค' };
}
if (!message) {
return { error: '๋ฉ์์ง๋ ํ์ ํญ๋ชฉ์
๋๋ค' };
}
// ์ด๋ฉ์ผ ์ ์ก ์๋ฎฌ๋ ์ด์
try {
await new Promise(resolve => setTimeout(resolve, 1000)); // ๋คํธ์ํฌ ์ง์ฐ ์๋ฎฌ๋ ์ด์
console.log('ํผ์ด ์ฑ๊ณต์ ์ผ๋ก ์ ์ถ๋์์ต๋๋ค!');
return { success: true, message: '๋ฉ์์ง๋ฅผ ๋ณด๋ด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค!' };
} catch (error) {
console.error('์ด๋ฉ์ผ ์ ์ก ์ค ์ค๋ฅ ๋ฐ์:', error);
return { error: '๋ฉ์์ง ์ ์ก์ ์คํจํ์ต๋๋ค. ๋ค์ ์๋ํด ์ฃผ์ธ์.' };
}
}
export default submitForm;
2. React ์ปดํฌ๋ํธ ์์ฑํ๊ธฐ:
์ด์ , ํผ์ ๋ ๋๋งํ๊ณ experimental_useFormState๋ฅผ ์ฌ์ฉํ์ฌ ํผ ์ํ๋ฅผ ๊ด๋ฆฌํ React ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
// ContactForm.jsx
'use client';
import { experimental_useFormState as useFormState } from 'react';
import submitForm from './server-actions';
function ContactForm() {
const [state, formAction] = useFormState(submitForm, null);
return (
);
}
export default ContactForm;
์ค๋ช :
'use client';: ์ด ์ง์๋ฌธ์ React์๊ฒ ์ด ์ปดํฌ๋ํธ๊ฐ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ์๋ฆฝ๋๋ค. ์ด๋experimental_useFormState๊ฐ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ ๋ด์์ ์๋ฒ ์ก์ ๊ณผ ์ํธ์์ฉํ๋ ๋ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.useFormState(submitForm, null): ์ด ํ ์ ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค: ์คํ๋ ์๋ฒ ์ก์ (submitForm)๊ณผ ์ด๊ธฐ ์ํ(์ด ๊ฒฝ์ฐnull). ํ์ฌ ํผ ์ํ์ ์๋ฒ ์ก์ ์ ํธ๋ฆฌ๊ฑฐํ๋ ํจ์๋ฅผ ํฌํจํ๋ ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค. ๋ฐํ๋ `formAction`์ ํผ์ `action` prop์ ์ ๋ฌ๋์ด์ผ ํฉ๋๋ค.form action={formAction}: ์ด๊ฒ์ ์๋ฒ ์ก์ ์ ํผ ์ ์ถ์ ๋ฐ์ธ๋ฉํฉ๋๋ค. ํผ์ด ์ ์ถ๋๋ฉดsubmitForm์ก์ ์ด ์๋ฒ์์ ์คํ๋ฉ๋๋ค.state?.error: ์๋ฒ ์ก์ ์์ ๋ฐํ๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค.state?.success: ์๋ฒ ์ก์ ์์ ๋ฐํ๋ ์ฑ๊ณต ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค.state?.pending: ์๋ฒ ์ก์ ์ด ์งํ๋๋ ๋์ ์๋์ผ๋ก true๋ก ์ค์ ๋์ด ์ ์ถ ๋ฒํผ์ ๋นํ์ฑํํ ์ ์์ต๋๋ค.
์ฝ๋ ์์ธ ์ค๋ช
์ฝ๋๊ฐ ๋จ๊ณ๋ณ๋ก ์ด๋ป๊ฒ ์๋ํ๋์ง ๋ถ์ํด ๋ณด๊ฒ ์ต๋๋ค.
์๋ฒ ์ก์ (server-actions.js)
'use server';: ์ด ์ง์๋ฌธ์ ํ์ผ์ ์๋ฒ ์ก์ ์ด ํฌํจ๋์ด ์์์ ํ์ํฉ๋๋ค. React๊ฐ ์ด ํ์ผ ๋ด์ ํจ์๋ค์ด ์๋ฒ์์ ์คํ๋์ด์ผ ํจ์ ์ดํดํ๋ ๋ฐ ์ค์ํฉ๋๋ค.async function submitForm(prevState, formData): ์ด ํจ์๋ ์๋ฒ ์ก์ ํจ์๋ฅผ ์ ์ํฉ๋๋ค. ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค:prevState(ํผ์ ์ด์ ์ํ)์formData(ํผ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๋FormData์ธ์คํด์ค).formData.get('name'),formData.get('email'),formData.get('message'): ์ด ์ค๋ค์FormData๊ฐ์ฒด์์ ํผ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํฉ๋๋ค.get()์ ์ธ์๋ ํผ์ ํด๋น ์ ๋ ฅ ํ๋์name์์ฑ์ ๋๋ค.- ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ: ์ฝ๋๋ ๋ชจ๋ ํ์ ํ๋๊ฐ ์๋์ง ํ์ธํ๊ธฐ ์ํด ๊ธฐ๋ณธ์ ์ธ ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํํฉ๋๋ค. ํ๋๊ฐ ๋๋ฝ๋ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ์ ์ค๋ฅ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ด๋ฉ์ผ ์ ์ก ์๋ฎฌ๋ ์ด์
: ์ฝ๋๋
await new Promise(resolve => setTimeout(resolve, 1000))๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฉ์ผ ์ ์ก์ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค. ์ด๋ ๋คํธ์ํฌ ์ง์ฐ์ ์๋ฎฌ๋ ์ด์ ํ๊ธฐ ์ํด 1์ด์ ์ง์ฐ์ ๋์ ํฉ๋๋ค. ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ด๋ฅผ ์ค์ ์ด๋ฉ์ผ ์ ์ก ๋ก์ง(์: Nodemailer ๋๋ SendGrid ์ฌ์ฉ)์ผ๋ก ๋์ฒดํด์ผ ํฉ๋๋ค. - ์ค๋ฅ ์ฒ๋ฆฌ: ์ฝ๋๋ ์ด๋ฉ์ผ ์ ์ก ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด
try...catch๋ธ๋ก์ ํฌํจํฉ๋๋ค. ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์ฝ์์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๊ณ ํด๋ผ์ด์ธํธ์ ์ค๋ฅ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. - ์ํ ๋ฐํ: ์๋ฒ ์ก์
์ ์ค๋ฅ ๋ฉ์์ง ๋๋ ์ฑ๊ณต ๋ฉ์์ง๋ฅผ ํฌํจํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ๊ฐ์ฒด๋
useFormStateํ ์ ํตํด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ ์ ๋ฌ๋๋ ์๋ก์ด ์ํ๊ฐ ๋ฉ๋๋ค.
ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ (ContactForm.jsx)
'use client';: ์ด ์ง์๋ฌธ์ ์ด ์ปดํฌ๋ํธ๊ฐ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ด๋ฉฐuseState๋ฐuseEffect์ ๊ฐ์ ํด๋ผ์ด์ธํธ ์ธก ํ ์ ์ฌ์ฉํ ์ ์์์ ๋ํ๋ ๋๋ค. ํ ์ ์ฌ์ฉํ๊ณ DOM๊ณผ ์ํธ์์ฉํ๊ธฐ ์ํด ํ์ํฉ๋๋ค.const [state, formAction] = useFormState(submitForm, null);: ์ด ์ค์experimental_useFormStateํ ์ ํธ์ถํฉ๋๋ค. ์ฒซ ๋ฒ์งธ ์ธ์๋กsubmitForm์๋ฒ ์ก์ ์, ๋ ๋ฒ์งธ ์ธ์๋ก ์ด๊ธฐ ์ํ(null)๋ฅผ ์ ๋ฌํฉ๋๋ค. ํ ์ ํ์ฌ ํผ ์ํ(state)์ ์๋ฒ ์ก์ ์ ํธ๋ฆฌ๊ฑฐํ๋ ํจ์(formAction)๋ฅผ ํฌํจํ๋ ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค.<form action={formAction}>: ์ด๊ฒ์ ํผ์action์์ฑ์formActionํจ์๋ก ์ค์ ํฉ๋๋ค. ํผ์ด ์ ์ถ๋๋ฉด ์ด ํจ์๊ฐ ํธ์ถ๋์ดsubmitForm์๋ฒ ์ก์ ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.<input type="text" id="name" name="name" />,<input type="email" id="email" name="email" />,<textarea id="message" name="message"></textarea>: ์ด๋ค์ ํผ์ ์ ๋ ฅ ํ๋์ ๋๋ค. ์ด ํ๋๋ค์name์์ฑ์ ์๋ฒ ์ก์ ์์formData.get('name'),formData.get('email'),formData.get('message')๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ๊ธฐ ๋๋ฌธ์ ์ค์ํฉ๋๋ค.<button type="submit" disabled={state?.pending}>์ ์ถ</button>: ์ด๊ฒ์ ํผ์ ์ ์ถ ๋ฒํผ์ ๋๋ค.disabled={state?.pending}์์ฑ์ ํผ์ด ์๋ฒ์ ์ ์ถ๋๋ ๋์ ๋ฒํผ์ ๋นํ์ฑํํ์ฌ ์ฌ์ฉ์๊ฐ ํผ์ ์ฌ๋ฌ ๋ฒ ์ ์ถํ๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.{state?.error && <p style={{ color: 'red' }}>{state.error}</p>}: ํผ ์ํ์ ์ค๋ฅ๊ฐ ์๋ ๊ฒฝ์ฐ ์กฐ๊ฑด๋ถ๋ก ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ ๋๋งํฉ๋๋ค. ์ค๋ฅ ๋ฉ์์ง๋ ๋นจ๊ฐ์์ผ๋ก ํ์๋ฉ๋๋ค.{state?.success && <p style={{ color: 'green' }}>{state.message}</p>}: ํผ์ด ์ฑ๊ณต์ ์ผ๋ก ์ ์ถ๋ ๊ฒฝ์ฐ ์กฐ๊ฑด๋ถ๋ก ์ฑ๊ณต ๋ฉ์์ง๋ฅผ ๋ ๋๋งํฉ๋๋ค. ์ฑ๊ณต ๋ฉ์์ง๋ ๋ น์์ผ๋ก ํ์๋ฉ๋๋ค.
๊ณ ๊ธ ์ฌ์ฉ๋ฒ ๋ฐ ๊ณ ๋ ค ์ฌํญ
์์ ์์ ๋ experimental_useFormState์ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ์ ๋ณด์ฌ์ฃผ์ง๋ง, ๋ ๋ณต์กํ ์ ํ๋ฆฌ์ผ์ด์
์์ ์ฌ์ฉํ ๋ ๊ณ ๋ คํด์ผ ํ ๋ช ๊ฐ์ง ๋ค๋ฅธ ์ธก๋ฉด์ด ์์ต๋๋ค.
๋๊ด์ ์ ๋ฐ์ดํธ (Optimistic Updates)
๋๊ด์ ์ ๋ฐ์ดํธ๋ฅผ ๊ตฌํํ์ฌ ๋ ๋ฐ์์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ๋๊ด์ ์ ๋ฐ์ดํธ๋ ์ฌ์ฉ์๊ฐ ํผ์ ์ ์ถํ ์งํ ์๋ฒ ์ก์ ์ด ์ฑ๊ณตํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ๊ณ UI๋ฅผ ์ฆ์ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์๋ฒ ์ก์ ์ด ์คํจํ๋ฉด ์ ๋ฐ์ดํธ๋ฅผ ๋๋๋ฆฌ๊ณ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
// ๋๊ด์ ์
๋ฐ์ดํธ ์์
async function submitForm(prevState, formData) {
// UI๋ฅผ ๋๊ด์ ์ผ๋ก ์
๋ฐ์ดํธ
// (์ผ๋ฐ์ ์ผ๋ก ๋ชฉ๋ก์ด๋ ํ
์ด๋ธ์ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ๊ฒ์ ํฌํจ)
const id = Date.now(); // ์์ ID
return {
optimisticUpdate: {
id: id,
name: formData.get('name'),
email: formData.get('email'),
}
}
}
// ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์:
const [state, formAction] = useFormState(submitForm, null);
// ๋๊ด์ ์
๋ฐ์ดํธ๋ฅผ ๋ ๋๋งํ๋ ์ํ
const [items, setItems] = useState([]);
useEffect(()=>{
if (state && state.optimisticUpdate) {
setItems(prev => [...prev, state.optimisticUpdate]);
}
}, [state])
์ด ๋จ์ํ๋ ์์ ์์ ์๋ฒ ์ก์
์ optimisticUpdate ์์ฑ์ ๋ฐํํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ์ด๋ฅผ ์ถ์ถํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์์ ๋ ๋๋ง๋๋ ๋ฐฐ์ด์ ์ถ๊ฐํ๋ ๋ฐ ์ฌ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ด๋ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์ ๋๊ธ ๋ชฉ๋ก์ ์ ๋๊ธ์ ์ถ๊ฐํ๋ ๊ฒ์ ๋ํ๋ผ ์ ์์ต๋๋ค.
์ค๋ฅ ์ฒ๋ฆฌ
ํจ๊ณผ์ ์ธ ์ค๋ฅ ์ฒ๋ฆฌ๋ ์ข์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํด ๋งค์ฐ ์ค์ํฉ๋๋ค. experimental_useFormState๋ ํผ ์ ์ถ ์ค์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๋ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค. ์ฌ์ฉ์์๊ฒ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ๊ณ ์ค๋ฅ๋ฅผ ์์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ง์นจ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
๋ค์์ ์ค๋ฅ ์ฒ๋ฆฌ์ ๋ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค:
- ๋ช ํํ๊ณ ๊ตฌ์ฒด์ ์ธ ์ค๋ฅ ๋ฉ์์ง ์ ๊ณต: ์ค๋ฅ ๋ฉ์์ง๋ ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ๋ฉฐ ๋ฐ์ํ ์ค๋ฅ์ ๋ํด ๊ตฌ์ฒด์ ์ด์ด์ผ ํฉ๋๋ค. "์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค."์ ๊ฐ์ ์ผ๋ฐ์ ์ธ ์ค๋ฅ ๋ฉ์์ง๋ ํผํ์ญ์์ค.
- ๊ด๋ จ ์ ๋ ฅ ํ๋ ๊ทผ์ฒ์ ์ค๋ฅ ๋ฉ์์ง ํ์: ์ค๋ฅ๋ฅผ ์ ๋ฐํ ์ ๋ ฅ ํ๋ ๊ทผ์ฒ์ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์๊ฐ ์ด๋ค ํ๋๋ฅผ ์์ ํด์ผ ํ๋์ง ๋ ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค.
- ์ค๋ฅ๋ฅผ ๊ฐ์กฐํ๊ธฐ ์ํด ์๊ฐ์ ์ ํธ ์ฌ์ฉ: ๋นจ๊ฐ์ ํ ์คํธ๋ ํ ๋๋ฆฌ์ ๊ฐ์ ์๊ฐ์ ์ ํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ฅ๊ฐ ์๋ ์ ๋ ฅ ํ๋๋ฅผ ๊ฐ์กฐํ์ญ์์ค.
- ์ค๋ฅ ์์ ์ ์ ์ ๊ณต: ๊ฐ๋ฅํ๋ค๋ฉด ์ค๋ฅ๋ฅผ ์์ ํ๊ธฐ ์ํ ์ ์์ ์ ๊ณตํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์ ํจํ์ง ์์ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์ ๋ ฅํ๋ฉด ์ฌ๋ฐ๋ฅธ ํ์์ ์ ์ํ์ญ์์ค.
์ ๊ทผ์ฑ ๊ณ ๋ ค ์ฌํญ
ํผ์ ๋ง๋ค ๋, ์ฅ์ ๊ฐ ์๋ ์ฌ๋๋ค๋ ํผ์ ์ฌ์ฉํ ์ ์๋๋ก ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์์ ์ผ๋์ ๋์ด์ผ ํ ๋ช ๊ฐ์ง ์ ๊ทผ์ฑ ๊ณ ๋ ค ์ฌํญ์ ๋๋ค:
- ์๋งจํฑ HTML ์ฌ์ฉ:
<label>,<input>,<textarea>์ ๊ฐ์ ์๋งจํฑ HTML ์์๋ฅผ ์ฌ์ฉํ์ฌ ํผ์ ๊ตฌ์กฐํํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ณด์กฐ ๊ธฐ์ ์ด ํผ์ ๊ตฌ์กฐ๋ฅผ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค. - ๋ชจ๋ ์
๋ ฅ ํ๋์ ๋ ์ด๋ธ ์ ๊ณต: ๋ชจ๋ ์
๋ ฅ ํ๋์ ๋ ์ด๋ธ์ ์ ๊ณตํ๊ธฐ ์ํด
<label>์์๋ฅผ ์ฌ์ฉํ์ญ์์ค.<label>์์์for์์ฑ์ ํด๋น ์ ๋ ฅ ํ๋์id์์ฑ๊ณผ ์ผ์นํด์ผ ํฉ๋๋ค. - ARIA ์์ฑ ์ฌ์ฉ: ARIA ์์ฑ์ ์ฌ์ฉํ์ฌ ํผ ์์์ ๋ํ ์ถ๊ฐ ์ ๋ณด๋ฅผ ๋ณด์กฐ ๊ธฐ์ ์ ์ ๊ณตํ์ญ์์ค. ์๋ฅผ ๋ค์ด,
aria-required์์ฑ์ ์ฌ์ฉํ์ฌ ์ ๋ ฅ ํ๋๊ฐ ํ์์์ ๋ํ๋ผ ์ ์์ต๋๋ค. - ์ถฉ๋ถํ ๋๋น ๋ณด์ฅ: ํ ์คํธ์ ๋ฐฐ๊ฒฝ์ ์ฌ์ด์ ์ถฉ๋ถํ ๋๋น๊ฐ ์๋์ง ํ์ธํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ ์๋ ฅ ์ฌ์ฉ์๊ฐ ํผ์ ๋ ์ฝ๊ฒ ์ฝ์ ์ ์์ต๋๋ค.
- ๋ณด์กฐ ๊ธฐ์ ๋ก ํ ์คํธ: ์คํฌ๋ฆฐ ๋ฆฌ๋์ ๊ฐ์ ๋ณด์กฐ ๊ธฐ์ ๋ก ํผ์ ํ ์คํธํ์ฌ ์ฅ์ ๊ฐ ์๋ ์ฌ๋๋ค๋ ์ฌ์ฉํ ์ ์๋์ง ํ์ธํ์ญ์์ค.
๊ตญ์ ํ(i18n) ๋ฐ ํ์งํ(l10n)
๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ๋ ๊ตญ์ ํ(i18n)์ ํ์งํ(l10n)๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ์ธ์ด, ๋ฌธํ ๋ฐ ์ง์ญ์ ๋ง๊ฒ ์กฐ์ ํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค.
experimental_useFormState๋ฅผ ์ฌ์ฉํ ๋์ i18n ๋ฐ l10n์ ๋ํ ๋ช ๊ฐ์ง ๊ณ ๋ ค ์ฌํญ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ค๋ฅ ๋ฉ์์ง ํ์งํ: ์ฌ์ฉ์์๊ฒ ํ์๋๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์งํํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ค๋ฅ ๋ฉ์์ง๊ฐ ์ฌ์ฉ์์ ์ ํธ ์ธ์ด๋ก ํ์๋ฉ๋๋ค.
- ๋ค๋ฅธ ๋ ์ง ๋ฐ ์ซ์ ํ์ ์ง์: ์ฌ์ฉ์์ ๋ก์บ์ ๋ฐ๋ผ ๋ค๋ฅธ ๋ ์ง ๋ฐ ์ซ์ ํ์์ ์ง์ํ์ญ์์ค.
- ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฐ๋ ์ธ์ด ์ฒ๋ฆฌ: ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฐ๋ ์ธ์ด(์: ์๋์ด, ํ๋ธ๋ฆฌ์ด)๋ฅผ ์ง์ํ๋ ๊ฒฝ์ฐ, ์ด๋ฌํ ์ธ์ด์์ ํผ ๋ ์ด์์์ด ์ฌ๋ฐ๋ฅด๊ฒ ํ์๋๋์ง ํ์ธํ์ญ์์ค.
- ๋ฒ์ญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ: i18next ๋๋ react-intl๊ณผ ๊ฐ์ ๋ฒ์ญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒ์ญ์ ๊ด๋ฆฌํ์ญ์์ค.
์๋ฅผ ๋ค์ด, ์ฌ์ ์ ์ฌ์ฉํ์ฌ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ์ฅํ ๋ค์ ์ฌ์ฉ์์ ๋ก์บ์ ๋ฐ๋ผ ์กฐํํ ์ ์์ต๋๋ค.
// i18next๋ฅผ ์ฌ์ฉํ ์์
import i18next from 'i18next';
i18next.init({
resources: {
en: {
translation: {
"name_required": "Name is required",
"email_required": "Email is required",
}
},
ko: {
translation: {
"name_required": "์ด๋ฆ์ ํ์ ํญ๋ชฉ์
๋๋ค",
"email_required": "์ด๋ฉ์ผ์ ํ์ ํญ๋ชฉ์
๋๋ค",
}
}
},
lng: 'ko', // ํ๊ตญ์ด๋ก ์ค์
fallbackLng: 'en',
interpolation: {
escapeValue: false // react๋ ์ด๋ฏธ xss๋ก๋ถํฐ ์์ ํจ
}
});
// ์๋ฒ ์ก์
์์:
if (!name) {
return { error: i18next.t("name_required") };
}
์ด ์์ ๋ i18next๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒ์ญ์ ๊ด๋ฆฌํฉ๋๋ค. i18next.t() ํจ์๋ ์ฌ์ฉ์์ ๋ก์บ์ ๋ฐ๋ผ ๋ฒ์ญ๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์กฐํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ์ํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋, ์ํํ๊ณ ํฌ์ฉ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋ช ๊ฐ์ง ์ฃผ์ ๊ณ ๋ ค ์ฌํญ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ์ด๋ฌํ ๊ณ ๋ ค ์ฌํญ์ ์ ๊ทผ์ฑ, ๋ฌธํ์ ๋ฏผ๊ฐ์ฑ, ์ฑ๋ฅ ์ต์ ํ ๋ฑ ๋ค์ํ ์์ญ์ ๊ฑธ์ณ ์์ต๋๋ค.
์๊ฐ๋
๋ ์ง์ ์๊ฐ์ ๋ค๋ฃฐ ๋ ์๊ฐ๋๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ฌ์ฉ์๋ ๋ค๋ฅธ ์๊ฐ๋์ ์์นํ ์ ์์ผ๋ฏ๋ก ๋ ์ง์ ์๊ฐ์ด ์ฌ์ฉ์์ ํ์ง ์๊ฐ๋๋ก ํ์๋๋๋ก ํด์ผ ํฉ๋๋ค.
๋ค์์ ์๊ฐ๋ ์ฒ๋ฆฌ์ ๋ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค:
- ๋ ์ง์ ์๊ฐ์ UTC๋ก ์ ์ฅ: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ ์ง์ ์๊ฐ์ UTC(ํ์ ์ธ๊ณ์)๋ก ์ ์ฅํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ ์๊ฐ๋์์ ๋ ์ง์ ์๊ฐ์ด ์ผ๊ด๋๊ฒ ์ ์ง๋ฉ๋๋ค.
- ์๊ฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ: Moment.js ๋๋ Luxon๊ณผ ๊ฐ์ ์๊ฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ ์ง์ ์๊ฐ์ ์ฌ์ฉ์์ ํ์ง ์๊ฐ๋๋ก ๋ณํํ์ญ์์ค.
- ์ฌ์ฉ์๊ฐ ์๊ฐ๋๋ฅผ ์ง์ ํ ์ ์๋๋ก ํ์ฉ: ์ฌ์ฉ์๊ฐ ํ๋กํ ์ค์ ์์ ์์ ์ ์๊ฐ๋๋ฅผ ์ง์ ํ ์ ์๋๋ก ํ์ฉํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ ํธํ๋ ์๊ฐ๋๋ก ๋ ์ง์ ์๊ฐ์ ํ์ํ ์ ์์ต๋๋ค.
ํตํ
์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ธ์ต ๊ฑฐ๋๋ฅผ ๋ค๋ฃจ๋ ๊ฒฝ์ฐ ๋ค๋ฅธ ํตํ๋ฅผ ์ง์ํด์ผ ํฉ๋๋ค. ์ฌ์ฉ์๋ ๋ค๋ฅธ ํตํ๋ฅผ ๊ฐ์ง ๋ค๋ฅธ ๊ตญ๊ฐ์ ์์นํ ์ ์์ต๋๋ค.
๋ค์์ ํตํ ์ฒ๋ฆฌ์ ๋ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค:
- ๊ฐ๊ฒฉ์ ์ผ๊ด๋ ํตํ๋ก ์ ์ฅ: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ๊ฒฉ์ ์ผ๊ด๋ ํตํ(์: USD)๋ก ์ ์ฅํ์ญ์์ค.
- ํตํ ๋ณํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ: ํตํ ๋ณํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๊ฒฉ์ ์ฌ์ฉ์์ ํ์ง ํตํ๋ก ๋ณํํ์ญ์์ค.
- ์ฌ๋ฐ๋ฅธ ํตํ ๊ธฐํธ๋ก ๊ฐ๊ฒฉ ํ์: ์ฌ์ฉ์์ ๋ก์บ์ ๋ฐ๋ผ ์ฌ๋ฐ๋ฅธ ํตํ ๊ธฐํธ๋ก ๊ฐ๊ฒฉ์ ํ์ํ์ญ์์ค.
- ์ฌ์ฉ์๊ฐ ํตํ๋ฅผ ์ ํํ ์ ์๋ ์ต์ ์ ๊ณต: ์ฌ์ฉ์๊ฐ ์ ํธํ๋ ํตํ๋ฅผ ์ ํํ ์ ์๋๋ก ํ์ฉํ์ญ์์ค.
๋ฌธํ์ ๋ฏผ๊ฐ์ฑ
๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ์ํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋ ๋ฌธํ์ ์ผ๋ก ๋ฏผ๊ฐํ๊ฒ ๋์ฒํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ๋ค๋ฅธ ๋ฌธํ์ ๊ท๋ฒ๊ณผ ๊ฐ์น๋ฅผ ์ธ์ํ๊ณ ๋ถ์พํ๊ฑฐ๋ ๋ฌด๊ฐ๊ฐํ ์ ์๋ ์ฝํ ์ธ ๋ฅผ ํผํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๋ฌธํ์ ๋ฏผ๊ฐ์ฑ์ ์ํ ๋ช ๊ฐ์ง ํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๊ด์ฉ๊ตฌ๋ ์์ด ์ฌ์ฉ ํผํ๊ธฐ: ๋ค๋ฅธ ๋ฌธํ๊ถ์ ์ฌ๋๋ค์ด ์ดํดํ์ง ๋ชปํ ์ ์๋ ๊ด์ฉ๊ตฌ๋ ์์ด ์ฌ์ฉ์ ํผํ์ญ์์ค.
- ์ด๋ฏธ์ง์ ๊ธฐํธ์ ์ฃผ์: ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉํ๋ ์ด๋ฏธ์ง์ ๊ธฐํธ์ ์ฃผ์ํ์ญ์์ค. ์ผ๋ถ ์ด๋ฏธ์ง์ ๊ธฐํธ๋ ๋ค๋ฅธ ๋ฌธํ์์ ๋ค๋ฅธ ์๋ฏธ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
- ๋ค๋ฅธ ์ข ๊ต์ ์ ๋ ์กด์ค: ๋ค๋ฅธ ์ข ๊ต์ ์ ๋ ์ ์กด์คํ๊ณ ์ข ๊ต ๋จ์ฒด์ ๋ถ์พ๊ฐ์ ์ค ์ ์๋ ์ฝํ ์ธ ๋ฅผ ํผํ์ญ์์ค.
- ๋ค๋ฅธ ๋ฌธํ์ ๊ท๋ฒ ์ธ์: ๋ค๋ฅธ ๋ฌธํ์ ๊ท๋ฒ๊ณผ ๊ฐ์น๋ฅผ ์ธ์ํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ์ผ๋ถ ๋ฌธํ์์๋ ์ง์ ์ ์ธ ๋๋ง์ถค์ด ๋ฌด๋กํ๋ค๊ณ ๊ฐ์ฃผ๋ฉ๋๋ค.
๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ์ํ ์ฑ๋ฅ ์ต์ ํ
์ ์ธ๊ณ ์ฌ์ฉ์๋ ๋ค์ํ ์ธํฐ๋ท ์ฐ๊ฒฐ ์๋์ ์ฅ์น ์ฑ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์์น๋ ์ฅ์น์ ๊ด๊ณ์์ด ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ํํ๊ณ ๋ฐ์์ ์ธ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- ์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ(CDN): CDN์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฐ(์: ์ด๋ฏธ์ง, JavaScript, CSS)์ ์ ์ธ๊ณ ์๋ฒ์ ๋ฐฐํฌํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์๋ณธ ์๋ฒ์์ ๋ฉ๋ฆฌ ๋จ์ด์ง ์ฌ์ฉ์์ ๋๊ธฐ ์๊ฐ์ ์ค์ผ ์ ์์ต๋๋ค.
- ์ด๋ฏธ์ง ์ต์ ํ: ์ด๋ฏธ์ง๋ฅผ ์์ถํ๊ณ ์ ์ ํ ํ์ผ ํ์(์: WebP)์ ์ฌ์ฉํ์ฌ ์ต์ ํํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ด๋ฏธ์ง์ ํ์ผ ํฌ๊ธฐ๊ฐ ์ค์ด๋ค๊ณ ํ์ด์ง ๋ก๋ ์๊ฐ์ด ํฅ์๋ฉ๋๋ค.
- ์ฝ๋ ๋ถํ : ์ฝ๋ ๋ถํ ์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์์ ๋ฐ๋ผ ๋ก๋ํ ์ ์๋ ๋ ์์ ์ฒญํฌ๋ก ๋๋์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๊ธฐ ๋ก๋ ์๊ฐ์ด ์ค์ด๋ญ๋๋ค.
- ์บ์ฑ: ์บ์ฑ์ ์ฌ์ฉํ์ฌ ์์ฃผ ์ก์ธ์คํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ธ๋ผ์ฐ์ ๋ ์๋ฒ์ ์ ์ฅํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๋ฒ์ ๋ณด๋ด๋ ์์ฒญ ์๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
- ์ถ์ ๋ฐ ๋ฒ๋ค๋ง: JavaScript ๋ฐ CSS ํ์ผ์ ์ถ์ํ๊ณ ๋ฒ๋ค๋งํ์ฌ ํ์ผ ํฌ๊ธฐ๋ฅผ ์ค์ด์ญ์์ค.
experimental_useFormState์ ๋์
experimental_useFormState๋ ์๋ฒ ์ก์
๊ณผ ํจ๊ป ํผ ๊ด๋ฆฌ์ ๋ํ ๊ฐ๋ ฅํ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํ์ง๋ง, ์์ง ์คํ ๋จ๊ณ์ ์๋ค๋ ์ ์ ๊ฐ์ํ ๋ ๋์ ์๋ฃจ์
์ ์๊ณ ์๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์ธ๊ธฐ ์๋ ๋์์
๋๋ค:
- React Hook Form: React Hook Form์ ๋น์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ์ฑ๋ฅ์ด ๋ฐ์ด๋๊ณ ์ ์ฐํ ํผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ต์ํ์ ๋ฆฌ๋ ๋๋ง๊ณผ ๋ฐ์ด๋ ์ฑ๋ฅ์ผ๋ก ์ ๋ช ํฉ๋๋ค. Yup ๋ฐ Zod์ ๊ฐ์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ํตํฉ๋ฉ๋๋ค.
- Formik: Formik์ ํผ ์ํ ๊ด๋ฆฌ, ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ ์ถ์ ๋จ์ํํ๋ ์ธ๊ธฐ ์๋ ํผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. React Hook Form๋ณด๋ค ๋ ๋์ ์์ค์ API๋ฅผ ์ ๊ณตํ๋ฉฐ ๋ณต์กํ ํผ์ ์ข์ ์ ํ์ ๋๋ค.
- Redux Form: Redux Form์ Redux์ ํตํฉ๋๋ ํผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ด๋ฏธ ์ํ ๊ด๋ฆฌ์ Redux๋ฅผ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ข์ ์ ํ์ ๋๋ค.
- useState ๋ฐ useRef ์ฌ์ฉ: ๊ฐ๋จํ ํผ์ ๊ฒฝ์ฐ, React์
useStateํ ์ ์ฌ์ฉํ์ฌ ์ง์ ํผ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณuseRef๋ฅผ ์ฌ์ฉํ์ฌ ํผ ๊ฐ์ ์ก์ธ์คํ ์๋ ์์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ ๋ง์ ์๋ ์ฒ๋ฆฌ๊ฐ ํ์ํ์ง๋ง ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํ ๊ธฐ๋ณธ ํผ์ ์ ํฉํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
experimental_useFormState๋ ํนํ ์๋ฒ ์ก์
๊ณผ ๊ฒฐํฉ๋ ๋ React ํผ ๊ด๋ฆฌ์์ ์ค์ํ ์ง์ ์ ๋ํ๋
๋๋ค. ํผ ์ํ๋ฅผ ์ฒ๋ฆฌํ๊ณ , ์๋ฒ ์ธก ๋ก์ง๊ณผ ์ํธ์์ฉํ๋ฉฐ, ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ ๋จ์ํ๋๊ณ ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์์ง ์คํ ๋จ๊ณ์ ์์ง๋ง, ์๋ก์ด ํ๋ก์ ํธ์ ๋ํด ํ์ํ๊ณ ๊ธฐ์กด ํ๋ก์ ํธ์ ๋ํด์๋ ์ฑ์ํด์ง์ ๋ฐ๋ผ ๊ณ ๋ คํด ๋ณผ ๊ฐ์น๊ฐ ์์ต๋๋ค. ํ
์ ํจ๊ณผ์ ์ด๊ณ ์ฑ
์๊ฐ ์๊ฒ ์ฌ์ฉํ๋ ค๋ฉด ์ต์ React ๋ฌธ์์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ์ ํ์ธํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค.
์ด ๊ฐ์ด๋์ ์ค๋ช ๋ ์์น์ ์ดํดํ๊ณ ํน์ ์๊ตฌ์ ๋ง๊ฒ ์กฐ์ ํจ์ผ๋ก์จ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ฐ์ํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ๊ฐ๋ ฅํ๊ณ ์ ๊ทผ ๊ฐ๋ฅํ๋ฉฐ ๊ธ๋ก๋ฒ ์ธ์์ ๊ฐ์ถ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ฑํํ๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์ฑ์ ํฅ์์ํฌ ๋ฟ๋ง ์๋๋ผ ํฌ์ฉ์ฑ๊ณผ ๋ฌธํ์ ๋ฏผ๊ฐ์ฑ์ ๋ํ ์ฝ์์ ๋ณด์ฌ์ฃผ๋ฉฐ, ๊ถ๊ทน์ ์ผ๋ก ๊ธ๋ก๋ฒ ๊ท๋ชจ์์ ํ๋ก์ ํธ์ ์ฑ๊ณต๊ณผ ๋๋ฌ ๋ฒ์์ ๊ธฐ์ฌํฉ๋๋ค.
React๊ฐ ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ experimental_useFormState์ ๊ฐ์ ๋๊ตฌ๋ ํ๋์ ์ธ ์๋ฒ ๋ ๋๋ง React ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ฐ ์ ์ ๋ ์ค์ํ ์ญํ ์ ํ ๊ฒ์
๋๋ค. ์ด๋ฌํ ๋๊ตฌ๋ฅผ ์ดํดํ๊ณ ํ์ฉํ๋ ๊ฒ์ ์๋์ ์์๋๊ฐ๊ณ ํ์ํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ๋ฐ ํ์์ ์ผ ๊ฒ์
๋๋ค.